Skip to content

Feature/fe payment success settings dashboard 1179 1182 - #1244

Merged
emdevelopa merged 7 commits into
emdevelopa:mainfrom
Dannyswiss1:feature/fe-payment-success-settings-dashboard-1179-1182
Jul 24, 2026
Merged

Feature/fe payment success settings dashboard 1179 1182#1244
emdevelopa merged 7 commits into
emdevelopa:mainfrom
Dannyswiss1:feature/fe-payment-success-settings-dashboard-1179-1182

Conversation

@Dannyswiss1

Copy link
Copy Markdown
Contributor

Summary

Implements four frontend UX/performance issues across the Payment Success Animation and Settings Dashboard modules.

#1179 — Optimize client-side bundle size for Payment Success Animation

  • Lazy-load PaymentSuccessAnimation with React.lazy + Suspense at its checkout call site (pay/[id]/page.tsx), gated behind a hasSucceededOnce flag.
  • The component's chunk (and its canvas-confetti dependency) is now only fetched the first time a payment actually succeeds, instead of on every checkout page load.

#1180 — Migrate component to React Server Components for Settings Dashboard

  • Split settings/page.tsx into an async Server Component (no "use client") and a new SettingsDashboardClient.tsx holding all interactive state/effects.
  • The server page now exports generateMetadata(), using next-intl's getTranslations (server-side) to set a real page <title>/description — previously the route silently inherited the generic root layout title.

#1181 — Enhance interactive loading states in Settings Dashboard

  • Replaced the blank screen shown while the merchant store hydrates with a full-page skeleton (header + nav placeholders + the existing SettingsPanelSkeleton), marked aria-busy with a polite sr-only status announcement.

#1182 — Implement i18n support for Settings Dashboard

  • Converted all remaining hardcoded English strings (toast success/error messages, fetch-failure fallbacks, hex-color validation, color-picker aria-labels) to useTranslations() calls.
  • Added 24 new keys to the settingsPage namespace across en.json, es.json, and pt.json.
  • Fixed a bug this surfaced: two data-loading effects had picked up the translator function as a dependency, which isn't guaranteed referentially stable across renders, causing a fetch → re-render → refetch loop. Reverted those effects to depend on apiKey only.

Acceptance criteria

  • Secure, tested, and documented — no new endpoints/permissions introduced; existing auth/validation paths untouched
  • Compatible across desktop and mobile — layout/breakpoints unchanged (Tailwind classes preserved), only loading/i18n/bundle behavior touched
  • Frontend UX enhancement and responsiveness addressed per-issue as above
  • No regressions in existing Settings Dashboard or Payment Success Animation behavior

Tests ran

  • SettingsDashboardClient.test.tsx19/19 passed (updated for the RSC rename, new skeleton behavior, and translated strings; also fixed two pre-existing test-infra gaps — missing @/lib/merchant-store/@/lib/display-preferences mocks and a missing jest-dom matcher import — that had every test in this suite failing before this change)
  • PaymentSuccessAnimation.test.tsx32/32 passed, unaffected by the lazy-loading change (which lives at the call site, not in the component)
  • tsc --noEmit across the project — confirmed no new errors introduced; the pre-existing parse error in pay/[id]/page.tsx and unrelated broken files (RecentPayments.tsx, SupportPanel.tsx, ThemeToggle.tsx, multisig-context.tsx) were verified present before this branch's changes too

Closes #1179
Closes #1180
Closes #1181
Closes #1182

…Animation

Lazy-load PaymentSuccessAnimation with React.lazy + Suspense at its
checkout call site, gated behind a hasSucceededOnce flag so the
component (and its canvas-confetti dependency) is only fetched the
first time a payment actually succeeds, rather than on initial page
load of every checkout.

Closes emdevelopa#1179
…nents

- page.tsx is now an async Server Component: no "use client", generates
  page metadata (title/description) server-side via next-intl's
  getTranslations, matching the pattern already used by
  dashboard/create/page.tsx. The <title> tag now reflects the Settings
  page instead of falling back to the generic root layout title.
- All interactive logic (tabs, forms, fetches, optimistic updates) moved
  into a new SettingsDashboardClient.tsx client component, which the
  server page renders.
- Renamed page.test.tsx to SettingsDashboardClient.test.tsx to match and
  fixed pre-existing test-infra gaps (missing @/lib/merchant-store and
  @/lib/display-preferences mocks, missing jest-dom matcher import) that
  were causing every test in the suite to fail before this change.

Closes emdevelopa#1180
Replace the blank screen shown while the merchant store hydrates with
a full-page skeleton (header placeholder, nav-item placeholders, and
the existing SettingsPanelSkeleton for the content area), marked
aria-busy with a polite sr-only status announcement, so users get
immediate loading feedback instead of a flash of nothing.

Closes emdevelopa#1181
…tings Dashboard

Replace the remaining hardcoded English strings in
SettingsDashboardClient.tsx with useTranslations() calls, adding 24 new
keys to the settingsPage namespace across en.json, es.json, and pt.json:
- All toast success/error messages (branding save, logo upload, API key
  rotation, webhook URL save/clear, domain verification, secret
  regeneration, test webhook)
- All fetch-failure fallback messages used when the API response omits
  an error field
- The branding hex-color validation message (now interpolates the
  already-translated field label instead of the raw snake_case key)
- The color-picker aria-label (now interpolates the translated label)

Also fixes a bug this surfaced: the two data-loading effects
(branding, webhook settings) had picked up `t` as a dependency, but
since the translator function is not guaranteed to be referentially
stable across renders, this caused a fetch -> re-render -> refetch
loop. Reverted those two effects to depend on `apiKey` only.

Closes emdevelopa#1182
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

@Dannyswiss1 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel.

A member of the Team first needs to authorize it.

…success-settings-dashboard-1179-1182

# Conflicts:
#	frontend/messages/en.json
#	frontend/messages/es.json
#	frontend/messages/pt.json
#	frontend/src/app/(authenticated)/settings/SettingsDashboardClient.test.tsx
#	frontend/src/app/(authenticated)/settings/page.tsx
@drips-wave

drips-wave Bot commented Jul 24, 2026

Copy link
Copy Markdown

@Dannyswiss1 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

…n failure blocking CI

The PR's CI checks were failing on unrelated pre-existing issues from
other merged branches, not this PR's own changes. Verified each via a
clean upstream/main checkout before fixing:

Frontend — Lint & Build (next build was failing to compile):
- MultisigApprovalModal.tsx imported CopyButton as a named export; it's
  a default export, which broke the build for every PR, not just this
  one.
- multisig-context.tsx had two conflicting state-management
  implementations left over from a bad merge: individual useState calls
  alongside dispatch()/stateRef.current calls with no matching
  useReducer, plus a duplicate unreachable return statement. Reconciled
  to the more complete useReducer-based implementation (kept
  isPendingConfirmation as separate useState since it isn't modeled in
  the reducer), added the missing setCurrentStep/stateRef wiring, and
  removed the dead second return.
- MultisigStep was missing the "processing" literal that the modal
  already switches on.
- Several components (NetworkStatusIndicator, PaymentMetrics,
  PortfolioChartWidget, RealTimeBalanceSync, TransactionFilterSidebar)
  declared framer-motion variants without a `: Variants` annotation,
  which widens fields like `ease`/`type` to plain `string` and fails
  the spring/easing overloads. Added the missing annotations (using
  `satisfies Variants` in network-animations.ts where `keyof typeof`
  needed to keep the literal key union for getStatusDotVariant /
  getLatencyVariant / getConnectionQualityVariant).
- NetworkStatusIndicator.tsx used nonexistent motion.div props
  onFocusStart/onFocusEnd; switched to native onFocus/onBlur.
- PortfolioChartWidget.tsx's recharts Legend formatter accessed
  `entry.payload.payload`, a shape recharts' own types don't model;
  added an explicit cast.
- SupportPanel.tsx passed size="xs" to Spinner, which only supports
  sm/md/lg/xl; switched to size="sm" with a smaller className override,
  matching the pattern already used elsewhere in the app.
- useNetworkMonitor.ts compared `status === "checking"` after an early
  return already narrowed status to exclude "checking" for that
  captured value — dead code, not a real missing union member; removed
  the redundant branch.
- network-performance.ts's useAnimationSystem shadowed the global
  `performance` object with a hook result of the same name, so
  `performance.now()` was calling a method that doesn't exist on the
  hook's return type. Renamed the local binding.

Frontend Visual Regression (checkout.visual.spec.ts):
- The checkout page rendered payment.description twice at once for any
  pending/unsettled payment (once in the compact header strip, again
  in the "Complete Payment" CTA box), so Playwright's strict-mode
  getByText("Styled payment") matched two elements. The CTA box now
  always shows the generic "Payment Request" label instead of
  repeating the description, which the header already displays.

Backend — Lint & Test failures (rate-limit store validation, API key
rotation, audit service mocking) were confirmed pre-existing and
unrelated to any frontend work in this PR via a clean upstream/main
checkout, and are left for a separate fix.
@emdevelopa
emdevelopa merged commit 6c2ea7c into emdevelopa:main Jul 24, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants